package com.hsogoo.avatar.spring;

import com.hsogoo.avatar.annotations.AvatarProvider;
import com.hsogoo.avatar.annotations.AvatarProviderControl;
import com.hsogoo.avatar.control.RateLimiterControl;
import com.hsogoo.avatar.exceptions.AvatarException;
import com.hsogoo.avatar.model.AvatarAddress;
import com.hsogoo.avatar.model.ProviderConfig;
import com.hsogoo.avatar.model.ProviderMethod;
import com.hsogoo.avatar.model.ProviderMethodConfig;
import com.hsogoo.avatar.registry.AvatarRegistry;
import com.hsogoo.avatar.registry.LimitControlRegistry;
import com.hsogoo.avatar.registry.ProviderMethodRegistry;
import com.hsogoo.avatar.registry.RegisterMeta;
import com.hsogoo.avatar.registry.RegistryLoader;
import com.hsogoo.avatar.registry.RegistryProvider;
import com.hsogoo.avatar.registry.ServiceMeta;
import com.hsogoo.avatar.utils.ConfigUtil;
import com.hsogoo.avatar.utils.NetworkUtil;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 处理带有AvatarProvider注解的bean
 * @Author huangsaigang
 * Created @2018/9/28.
 */
@Component
public class AvatarProviderBeanPostProcessor implements BeanPostProcessor {


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //如果带有AvatarProvider注解的类需要发布服务，并注册到注册中心
        if(bean.getClass().isAnnotationPresent(AvatarProvider.class)){
            AvatarProvider avatarProvider = bean.getClass().getAnnotation(AvatarProvider.class);
            String beanClassName = bean.getClass().getInterfaces()[0].getName();
            Method[] methods = bean.getClass().getDeclaredMethods();
            for(Method method : methods){
                StringBuilder sb = new StringBuilder();
                sb.append(beanClassName).append(".").append(method.getName());
                //支持方法重载
                Class[] paramTypes = method.getParameterTypes();
                if(paramTypes != null && paramTypes.length > 0){
                    for(Class param : paramTypes){
                        sb.append("#").append(param.getSimpleName());
                    }
                }
                String key = sb.toString();
                AvatarProviderControl avatarProviderControl = method.getAnnotation(AvatarProviderControl.class);
                //注册到本地服务
                ProviderMethodRegistry.register(key, new ProviderMethod(bean, method, providerConfig(avatarProvider), providerMethodConfig(avatarProviderControl)));
                //注册provider级限流器
                if(avatarProvider.limit() > 0){
                    LimitControlRegistry.register(beanClassName, new RateLimiterControl(avatarProvider.limit()));
                }
                //注册provider方法级限流器
                if(avatarProviderControl != null && avatarProviderControl.limit() > 0){
                    LimitControlRegistry.register(key, new RateLimiterControl(avatarProviderControl.limit()));
                }
            }
            AvatarRegistry registry = RegistryProvider.getRegistry(avatarProvider.registry());
            RegisterMeta registerMeta = new RegisterMeta();
            int port = ConfigUtil.getInstance().getAvatarPort();
            String host = NetworkUtil.getLocalIpString();
            AvatarAddress address = new AvatarAddress(host, port);
            ServiceMeta serviceMeta = new ServiceMeta(avatarProvider.group(), beanClassName, avatarProvider.version());
            registerMeta.setAddress(address);
            registerMeta.setServiceMeta(serviceMeta);
            registry.register(registerMeta);

        }
        return bean;
    }

    private ProviderConfig providerConfig(AvatarProvider avatarProvider){
        ProviderConfig providerConfig = new ProviderConfig();
        if(avatarProvider != null){
            providerConfig.setGroup(avatarProvider.group());
            providerConfig.setRegistry(avatarProvider.registry());
            providerConfig.setLimit(avatarProvider.limit());
            providerConfig.setVersion(avatarProvider.version());
            providerConfig.setExecutor(avatarProvider.executor());
        }
        return providerConfig;
    }

    private ProviderMethodConfig providerMethodConfig(AvatarProviderControl avatarProviderControl){

        ProviderMethodConfig providerMethodConfig = new ProviderMethodConfig();
        if(avatarProviderControl != null){
            providerMethodConfig.setFallback(avatarProviderControl.fallback());
            providerMethodConfig.setLimit(avatarProviderControl.limit());
        }
        return providerMethodConfig;
    }
}
